#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

typedef struct{
	int x, y;
}Punto;

void inicializar (void);
void redimensiona (int alto, int ancho);
void dibuja (void);
void teclado (unsigned char key, int cx, int cy);
void raton (int boton, int estado, int cx, int cy);
void bresenham (Punto p1, Punto p2);
void limpiaScreen ();

Punto pts[2];
int numPtos;
int screen[640][480];
int conexo;

int main(int argc, char** argv) {
   
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize (640, 480);
   glutInitWindowPosition (100, 105);
   glutCreateWindow (argv[0]);
   inicializar();
   
   glutDisplayFunc(dibuja);
   glutReshapeFunc(redimensiona);
   glutKeyboardFunc(teclado);
   glutMouseFunc(raton);
   glutMainLoop();
   
   return 0;
}

void inicializar () {
   limpiaScreen();
   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
   numPtos = 0;
   conexo = 0;
   
}

//Pongamos la proyeccion que coincida con los pixeles de la pantalla de uno a uno

void redimensiona (int ancho, int alto) {
   
   glViewport (0, 0, ancho, alto);
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
  
   glOrtho(0.0, (float)ancho, (float)alto, 0.0, -1.0, 1.0);
 
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}

void teclado (unsigned char key, int cx, int cy) {
	
	switch (key) {
		case 27:
		   exit(0);
		break;
		
		case 'C':
		case 'c':
			conexo = !(conexo);
		break;
		
		default: break;
	}
	
	glutPostRedisplay();
}


void raton (int boton, int estado, int cx, int cy) {
	
	if (boton == GLUT_LEFT_BUTTON && estado == GLUT_DOWN) {
		
		if (numPtos < 2) {
			pts[numPtos].x = cx;
			pts[numPtos].y = cy;
			numPtos++;
		} else {
			limpiaScreen();
			pts[0].x = cx;
			pts[0].y = cy;
			numPtos = 1;
		}
		screen[cx][cy] = 1;
	}
	
	glutPostRedisplay();
}

void dibuja (void) {
	int i, j;
	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	glColor3f(1.0, 0.0, 0.0);
	
	limpiaScreen();
	
	if (numPtos == 2) {
		bresenham(pts[0], pts[1]);
	} else {
		glPointSize(2.0);
		glColor3f(1.0, 1.0, 0.0);
		glBegin(GL_POINTS);
			glVertex3i(pts[0].x, pts[0].y, 0);
		glEnd();
	}
	glPointSize(1.0);
	glColor3f(1.0, 0.0, 0.0);
	glBegin(GL_POINTS);
	for (i = 0; i < 640; i++) {
      for (j = 0; j < 480; j++) {
      	  if (screen[i][j] != 0) {
      	  	  glVertex3i(i, j, 0);
	      }
      }
    }
	glEnd();
	    
	glutSwapBuffers();
}


void bresenham (Punto p1, Punto p2) {
	int x0, x1, y0, y1;
	
	x0 = p1.x;
	y0 = p1.y;
	x1 = p2.x;
	y1 = p2.y;
	
	int steep = abs(y1 - y0) > abs(x1 - x0);
	int i;
	
	//La pendiente es menor que cero ambiemos las x, por las y
	if (steep) {
		x0 = p1.y;
		y0 = p1.x;
		x1 = p2.y;
		y1 = p2.x;
	}
    
    // x0 esta despues de x1, cambiemos el orden los ceros por los unos
	if (x0 > x1) {	
		int aux;
		aux = x0;
		x0 = x1;
		x1 = aux;
		aux = y0;
		y0 = y1;
		y1 = aux;
    }
    
	int deltax = x1 - x0;
	int deltay = abs(y1 - y0);
	int error = deltax / 2;
	int ystep;
	int y = y0;
	
	if (y0 < y1) {
		ystep = 1;
	} else {
		ystep = -1;
	}
	
	for (i = x0; i <= x1; i++) {
        
        if (steep) {
         	screen[y][i] = 1;
		} else { 
			screen[i][y] = 1;
		}
        
        error -= deltay;
        
        if (error < 0) {
             y += ystep;
             error += deltax;
             if (conexo) {
             	if (steep) {
         			screen[y][i] = 1;
				} else { 
					screen[i][y] = 1;
				}
			}
        }
    }
	return;
}

void limpiaScreen () {
   int i, j;
   
   for (i = 0; i < 640; i++) {
      for (j = 0; j < 480; j++) {
      	  screen[i][j] = 0;
      }
   }
   
   return;
}
